#pragma once

#include "sock.hpp"
#include <iostream>
#include <functional>
#include <poll.h>
#include <unistd.h>

#define FD_NUM 1024

using namespace std;

using func = function<string(const string&)>;

const int defaultfd = -1;

/*
poll对比select的优势
1.fd数组的容量不受限制 可以设置动态扩容方法
2.在每轮调用前不用像select一样重新设置位图结构 减少遍历的次数

两者的共同缺陷
1.需要自行维护辅助数组
2.每当读事件发生时都要将整个数组遍历一遍确认是哪些fd就绪
*/
class pollServer
{
public:
    pollServer(uint16_t port, func f)
    : _port(port),
      _f(f),
      _listensock(-1),
      _rfds(nullptr)
    {}

    ~pollServer()
    {
        if (_listensock > 0)
            close(_listensock);
        delete[] _rfds;
    }

    void initServer()
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        _rfds = new struct pollfd[FD_NUM];
        for (int i = 0; i < FD_NUM; i++)
        {
            _rfds[i].fd = defaultfd;
            _rfds[i].events =  _rfds[i].revents = 0;
        }
        _rfds[0].fd = _listensock;
        _rfds[0].events = POLLIN;
    }

    void startServer()
    {
        while (true)
        {
            //select在调用前需要重新设置位图结构 而poll的events在添加fd时就已设置好 除非要新增事件 否则无需更改
            int n = poll(_rfds, FD_NUM, -1);//>0 时限内等待  =0 非阻塞 -1阻塞
            switch (n)
            {
            case 0:
                cout << "time out" << endl;
                break;
            case -1:
                cout << "poll error: " << strerror(errno) << endl;
                break;
            default:
                cout << "have event ready" << endl;
                handlerEvent();
                break;
            }
        }        
    }

    //{} [] () - & 
    void handlerEvent()
    {
        for (int i = 0; i < FD_NUM; i++)
        {
            if (_rfds[i].fd == defaultfd || (_rfds[i].events & POLLIN) == 0 || (_rfds[i].revents & POLLIN) == 0)
                continue;
            if (_rfds[i].fd == _listensock)//有新连接到来
            {
                //cout << "get a new link" << endl;
                Accepter();
            }
            else//已有连接中有读事件就绪
            {
                Receiver(i);
            }
        }
    }

    void Accepter()
    {
        struct sockaddr_in client;
        memset(&client, 0, sizeof client);
        int sock = Sock::Accept(_listensock, &client);
        string clientip = inet_ntoa(client.sin_addr);
        uint16_t clientport = ntohs(client.sin_port);
        cout << "accept a new link " << clientip << "[" << clientport << "]" << endl;
        //poll没有使用位图结构 所以在设置fd数量时没有限制 如果将struct pollfd数组设置为动态扩容 这里就不用判断数组是否已满
        int i = 0;
        for (i; i < FD_NUM; i++)
        {
            if (_rfds[i].fd != defaultfd)
                continue;
            else
                break;
        }
        // 判断服务器是否还有能力接收新连接 select最多同时维护1024个文件描述符
        if (i == FD_NUM)
        {
            cout << "server is full, please wait" << endl;
            close(sock);
        }
        else
        {
            _rfds[i].fd = sock;
            _rfds[i].events = POLLIN;
            _rfds[i].revents = 0;
        }
        Print();
    }

    void Receiver(int pos)
    {
        char buffer[1024];
        int sock = _rfds[pos].fd;
        int n = recv(sock, buffer, sizeof buffer, 0);
        if (n > 0)
        {
            buffer[n - 1] = 0;
            cout << "#client: " << buffer << endl;
        }
        else if (n == 0)
        {
            cout << "client quit" << endl;
            close(sock);
            _rfds[pos].fd = defaultfd;
            _rfds[pos].events = _rfds[pos].revents = 0;
            return;
        }
        else
        {
            cout << "recv error: " << strerror(errno) << endl;
            close(sock);
            _rfds[pos].fd = defaultfd;
            _rfds[pos].events = _rfds[pos].revents = 0;
            return;
        }
        string response = _f(buffer);
        //write(sock, response.c_str(), response.size());
        send(sock, response.c_str(), response.size(), 0);
    }

    void Print()
    {
        cout << "fdlist: ";
        for (int i = 0; i < FD_NUM; i++)
        {
            if (_rfds[i].fd == defaultfd)
                continue;
            cout << _rfds[i].fd << " ";
        }
        cout << endl;
    }


private:
    int _listensock;
    uint16_t _port;
    func _f;
    struct pollfd* _rfds;
};